package org.aerie.forest.core.frame.rebar.entity;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.aerie.forest.core.brick.exception.ExceptionPack;
import org.aerie.forest.core.brick.exception.custom.ForestException;
import org.aerie.forest.core.brick.exception.custom.runtime.ForestLogInitException;
import org.aerie.forest.core.brick.exception.custom.runtime.ForestRuntimeException;
import org.aerie.forest.core.frame.init.ForestFrameContext;
import org.aerie.forest.core.frame.rebar.AbstractForestSingleFrame;
import org.aerie.forest.core.frame.rebar.exception.runtime.ForestRebarIllegalException;

/**
 * 
 * @description forest架构元素
 *
 * @author quark
 * @organization aerie
 * @date 2020年2月10日 下午8:11:54
 * @version 1.2.0
 */
public abstract class AbstractForestRebar extends AbstractForestSingleFrame {

	/**
	 * @description 校验器
	 *
	 * @author quark
	 * @organization aerie
	 * @date 2020年5月12日 上午9:14:53
	 * @version 1.2.0
	 */
	protected final class Calibrator {

		/**
		 * @description 合法性校验器集合
		 * 
		 * @author quark
		 * @date 2020年2月27日 上午9:46:16
		 * @version 1.2.0
		 */
		private List<AbstractForestValidityCheck<? extends AbstractForestRebar>> forestRebarValidityChecks = new ArrayList<>();

		/**
		 * Construction
		 * 
		 *
		 * @author quark
		 * @date 2020年5月12日 上午9:49:23
		 * @version 1.2.0
		 */
		private Calibrator() {
			super();
		}

		/**
		 * @description 添加合法性校验块
		 * @param forestValidityCheck 合法性校验块
		 *
		 * @author quark
		 * @date 2020年5月12日 上午10:59:03
		 * @version 1.2.0
		 */
		public void addValidityCheck(AbstractForestValidityCheck<? extends AbstractForestRebar> forestValidityCheck) {
			if (forestValidityCheck == null) {
				LOGGER.warn("添加的合法性校验块为空");
				return;
			}
			forestRebarValidityChecks.add(forestValidityCheck);
			LOGGER.trace("{}合法性校验块添加完成", forestValidityCheck.getGenericityZclass().getSimpleName());
		}

		/**
		 * @description 校验
		 * @param forestRebar forest架构元素
		 *
		 * @date 2020年2月27日 上午9:47:13
		 * @version 1.2.0
		 */
		private final void isLegal(AbstractForestRebar forestRebar) throws Exception {
			// 校验所有的校验法则
			LOGGER.trace("开始对【{}】forest架构元素单例模式校验", forestRebar.getForestRebarName());
			for (AbstractForestValidityCheck<?> forestRebarValidityCheck : forestRebarValidityChecks) {
				if (!forestRebarValidityCheck.getGenericityZclass().isAssignableFrom(forestRebar.getClass())) {
					throw new ForestRuntimeException("forest架构元素【" + forestRebar.getClass().getName() + "】合法性校验块泛型错误") {

						/**
						 * @description 序列化编号
						 * 
						 * @author quark
						 * @date 2020-8-13 22:48:43
						 * @version 2.0.1
						 */
						private static final long serialVersionUID = 1L;
					};
				}
				forestRebarValidityCheck.isLegal(forestRebar);
			}
			LOGGER.trace("forest架构元素【{}】单例模式校验合格", forestRebar.getForestRebarName());
		}
	}

	/**
	 * @description 校验器
	 * 
	 * @author quark
	 * @date 2020年5月12日 上午9:34:01
	 * @version 1.2.0
	 */
	protected final Calibrator calibrator = new Calibrator();

	/**
	 * @description 合法性校验块
	 * 
	 * @author quark
	 * @date 2020年5月12日 上午9:57:52
	 * @version 1.2.0
	 */
	private final AbstractForestValidityCheck<AbstractForestRebar> forestValidityCheck = new AbstractForestValidityCheck<AbstractForestRebar>(
			"") {

		@Override
		protected void beginCheck(AbstractForestRebar forestRebar) throws Exception {
			// 校验内部类
			checkInnerClassForestRebarReveal(forestRebar.getClass());
			// 校验rebar本身
			checkForestRebarReveal(forestRebar.getClass());
		}

		/**
		 * @description 校验forestRebar有没有单例对象泄露风险【无法完全杜绝泄露：方法内部无法校验，只能一定程度上提醒程序员】
		 * @param forestRebarClass 被校验的forestRebar
		 *
		 * @author quark
		 * @date 2020-8-20 23:26:32
		 * @version 2.0.1
		 * @throws Exception
		 */
		private void checkForestRebarReveal(Class<? extends AbstractForestRebar> forestRebarClass) throws Exception {
			try {
				int modifiers = forestRebarClass.getModifiers();
				// 校验rebar的类修饰符
				if (!Modifier.isPublic(modifiers) || !Modifier.isFinal(modifiers))
					throw new ForestException("rebar的类修饰符必须是public，final") {

						/**
						 * @description 序列化编号
						 * 
						 * @author quark
						 * @date 2020-8-22 0:28:24f
						 * @version 2.0.1
						 */
						private static final long serialVersionUID = 1L;
					};
				// 校验构造器
				Constructor<? extends AbstractForestRebar> declaredConstructor = getStaticInnerClassConstructor(
						forestRebarClass);
				Constructor<?>[] declaredConstructors = Optional.ofNullable(forestRebarClass.getDeclaredConstructors())
						.filter(p1 -> p1.length == 2).orElseThrow(() -> new ForestException("rebar有且只能有一个构造器") {

							/**
							 * @description 序列化编号
							 * 
							 * @author quark
							 * @date 2020-8-22 0:38:00
							 * @version 2.0.1
							 */
							private static final long serialVersionUID = 1L;
						});
				boolean declaredConstructorSign = false;
				for (Constructor<?> constructor : declaredConstructors) {
					if (constructor.equals(declaredConstructor)) {
						if (declaredConstructorSign) {
							throw new ForestException("内部构造器异常，请联系架构师") {

								/**
								 * @description 序列化编号
								 * 
								 * @author quark
								 * @date 2020-8-22 0:38:00
								 * @version 2.0.1
								 */
								private static final long serialVersionUID = 1L;
							};
						}
						declaredConstructorSign = true;
						continue;
					}
					if (!Modifier.isPrivate(constructor.getModifiers())) {
						throw new ForestException("rebar构造器必须是私有的") {

							/**
							 * http://www.52qingyin.cn/dielian-10banben.html * @description 序列化编号
							 * 
							 * @author quark
							 * @date 2020-8-22 0:38:00
							 * @version 2.0.1
							 */
							private static final long serialVersionUID = 1L;
						};
					}
				}
				// 校验属性
				Field[] declaredFields = forestRebarClass.getDeclaredFields();
				for (Field declaredField : declaredFields) {
					Class<?> fieldType = declaredField.getType();
					if (fieldType.isAssignableFrom(forestRebarClass)) {
						throw new ForestException("rebar属性存在泄露风险") {

							/**
							 * @description 序列化编号
							 * 
							 * @author quark
							 * @date 2020-8-22 0:38:00
							 * @version 2.0.1
							 */
							private static final long serialVersionUID = 1L;
						};
					}
				}
			} catch (Exception e) {
				throw new ExceptionPack("forest架构元素：【" + forestRebarClass.getName() + "】校验器不通过异常", e);
			}

		}

		/**
		 * @description 获得因为静态内部类单例对象而生成的构造器
		 * @param forestRebarClass 被校验的forestRebar
		 * @return 获得的构造器类
		 * @throws Exception 获取的异常
		 *
		 * @author quark
		 * @date 2020-8-26 17:20:20
		 * @version 2.0.1
		 */
		private Constructor<? extends AbstractForestRebar> getStaticInnerClassConstructor(
				Class<? extends AbstractForestRebar> forestRebarClass) throws Exception {

			try {
				return forestRebarClass.getDeclaredConstructor(forestRebarClass);
			} catch (NoSuchMethodException | SecurityException e) {
				try {
					return forestRebarClass.getDeclaredConstructor(Class.forName(forestRebarClass.getName() + "$1"));
				} catch (NoSuchMethodException | SecurityException | ClassNotFoundException e1) {
					throw new ExceptionPack("静态内部类特殊构造获取失败", e);
				}
			}

		}

		/**
		 * @description 校验forestRebar的内部类有没有单例对象泄露风险
		 * @param forestRebarClass 被校验的forestRebar
		 *
		 * @author quark
		 * @date 2020-8-9 15:58:55
		 * @version 2.0.1
		 */
		private void checkInnerClassForestRebarReveal(Class<? extends AbstractForestRebar> forestRebarClass) {
			// 获得内部类
			Class<?>[] declaredClasses = forestRebarClass.getDeclaredClasses();
			// 校验各内部类
			for (Class<?> declaredClass : declaredClasses) {
				// 默认的静态内部类单例的类名为ForestInstance
				if (declaredClass.getSimpleName().equals("ForestInstance")) {
					if (checkStaticInnerClass(declaredClass, forestRebarClass))
						return;
					throw new ForestRebarIllegalException(forestRebarClass, "静态内部类单例校验失败");
				}
			}
			throw new ForestRebarIllegalException(forestRebarClass, "未检测到合法的静态内部类单例");
		}

		/**
		 * @description 校验静态内部类单例
		 * @return 校验结果
		 *
		 * @author quark
		 * @date 2020-8-9 22:59:482
		 * @version 2.0.1
		 */
		private boolean checkStaticInnerClass(Class<?> staticInnerClass,
				Class<? extends AbstractForestRebar> forestRebarClass) {
			if (!staticInnerClass.getSuperclass().equals(Object.class)) {
				LOGGER.debug("error: 【{}】静态内部类单例必须是Object的直接子类", staticInnerClass.getName());
				return false;
			}
			int modifiers = staticInnerClass.getModifiers();
			// final为了防止被集成
			if (!Modifier.isStatic(modifiers) || !Modifier.isPrivate(modifiers) || !Modifier.isFinal(modifiers)) {
				LOGGER.debug("error: 【{}】静态内部类单例必须是私有静态最终的", staticInnerClass.getName());
				return false;
			}
			Constructor<?>[] declaredConstructors = staticInnerClass.getDeclaredConstructors();
			if (declaredConstructors.length != 1 || !Modifier.isPrivate(declaredConstructors[0].getModifiers())) {
				LOGGER.debug("error: 【{}】静态内部类单例唯一构造器必须私有化", staticInnerClass.getName());
				return false;
			}
			Field[] declaredFields = staticInnerClass.getDeclaredFields();
			// 静态内部类有且只能有一个，而且是所需的单例类
			Field declaredField = declaredFields[0];
			if (declaredFields.length != 1 || !declaredField.getType().equals(forestRebarClass)) {
				LOGGER.debug("error: 【{}】静态内部类单例唯一单例属性", staticInnerClass.getName());
				return false;
			}
			int declaredFieldModifiers = declaredField.getModifiers();
			// 静态内部类里的单例必须是private，static，final
			if (!Modifier.isPrivate(declaredFieldModifiers) || !Modifier.isStatic(declaredFieldModifiers)
					|| !Modifier.isFinal(declaredFieldModifiers)) {
				LOGGER.debug("error: 【{}】静态内部类单例属性必须私有静态最终的", staticInnerClass.getName());
				return false;
			}
			// 静态内部类里的单例不能存在方法
			if (staticInnerClass.getDeclaredClasses().length != 0) {
				LOGGER.debug("error: 【{}】静态内部类单例禁止定义方法", staticInnerClass.getName());
				return false;
			}
			return true;
		}

	};

	/**
	 * Construction
	 * 
	 * @param forestRebarName forestRebar的名称
	 *
	 * @date 2020年4月21日 下午5:54:09
	 * @version 1.2.0
	 */
	protected AbstractForestRebar(String forestRebarName) {
		super(forestRebarName);
		// forest框架必须在forest初始化的前提下才能创建
		if (!ForestFrameContext.INSTANCE.getLogInitSign()) {
			throw new ForestLogInitException();
		}
		calibrator.addValidityCheck(forestValidityCheck);
	}

	/**
	 * @description 获得forest架构元素的名称
	 * @return forest架构元素的名称
	 *
	 * @date 2020年2月27日 上午9:46:51
	 * @version 1.2.0
	 */
	public String getForestRebarName() {
		return forestFrameName;
	}

	/**
	 * @description 合法性校验
	 *
	 * @author quark
	 * @date 2020年5月12日 上午11:10:42
	 * @version 1.2.0
	 */
	public final void isLegal() throws Exception {
		calibrator.isLegal(this);
		LOGGER.debug("forest架构元素:{}校验合格", forestFrameName);
	}

}
